package edu.nf.test.demo;

import io.github.classgraph.ClassInfo;
import io.github.classgraph.ClassInfoList;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author CSY
 * @date 2025 - 04 - 16
 * 容器工厂 - 将扫描到包含@Conponent注解的所有类存储到容器中
 * 容器 - List、Map、Set
 */
public class ContainerFactory {
    /**
     * 容器 - 存储键值
     */
    private final Map<String,Object> container = new HashMap<>();

    private final FieldInjectHandler fieldInjectHandler = new FieldInjectHandler();

    /**
     * 构造方法根据包名初始化容器
     * @param pakageName
     */
    public ContainerFactory(String pakageName) {
        init(pakageName);
        processInject();
    }

    /**
     * 初始化容器的值
     * 先根据ScanUtils工具类来获取到所有的类集合
     * 循环遍历所有的类
     * 使用ClassInfoList对象中的API方法将类转换为Class对象
     * 判断是否存在@Component注解
     * 如果存在那么就获取到注解的值
     * 实例化对象 - 根据Class对象进行实例化
     * 获得的注解值和实例化的对象存入到map集合中已达到初始化容器的目的
     * @param pakageName
     */
    private void init(String pakageName){
        ClassInfoList scan = ScanUtils.scan(pakageName);
        for (ClassInfo classInfo : scan) {
            //转换为Class对象
            Class<?> clazz = classInfo.loadClass();

            if (clazz.isAnnotationPresent(Component.class)) {
                try {
                    String name = clazz.getAnnotation(Component.class).value();
                    Object instance = clazz.getConstructor().newInstance();
                    container.put(name,instance);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 在实例化该工厂的时候我就要进行依赖注入
     * 为所有的包含Inject注解的字段注入值
     * 因为字段的初始值是null
     */
    private void processInject(){
        //循环遍历容器的键 - 并获取到容器中存储的所有对象
        for (String key : container.keySet()) {

            Object instance = container.get(key);

            fieldInjectHandler.handle(instance,this);
        }
    }

    public <T> T getBean(String name) {
        if (container.containsKey(name)) {
            return (T) container.get(name);
        }
        throw new RuntimeException("不存在："+name);
    }
}
